# -- coding: utf-8 --
# @time : 2023/4/18
# @author : 周梦泽
# @file : promotion.py
# @software: pycharm
"""
# promotion 推广
"""
import re
import time
import pyperclip
from DrissionPage.common import Keys, ActionChains
from common.logger.log import log_
from common.utils.web_page_util import MockTap, Tap, Input
from common.utils.web_page_util import create_page
from autoTask.taobao.taobao_login import Login
from common.utils.ExcelUtil import copy_excel_section


class AddCommodity:
    """
    直通车添加商品关键词
    :param params: 任务参数
    """

    def __init__(self, params: dict, excel_path: str, sheet_name: str = "补单周期"):
        """
        初始化参数
        :param params: 任务参数 其中包含：
                account: 账号
                password: 密码
        """
        self.account = params['account']
        self.password = params['password']
        self.percent = params['percent']
        self.price_cap = params['priceCap']
        self.target_product_map = params['targetProductMap']
        # self.product_del_promotion_word = params['delPromotionWord']

        # 商品id
        # self.product_id_list = [target['productId'] for target in target_product_map] if target_product_map else []
        # print(self.product_id_list)
        self.is_test_execute = params.get('isTestExecute')  # 是否测试执行
        self.matches_type = params['matchesType']  # 精准匹配/广泛匹配
        self.excel_path = excel_path  # excel路径
        self.sheet_name = sheet_name  # 表格名
        self.page = create_page()
        self.ac = ActionChains(self.page)

    def go_through_train(self):
        """
        1去直通车
        2点击推广
        3点击标准计划
        4获取每个[推广计划名称]的链接
        5选中表格中的[关键词]列复制到剪切板
        :return:
        """
        if not any(x in self.page.url for x in ["subway.simba.taobao.com", "sycm.taobao.com"]):
            self.page, _ = Login(self.account, self.password).execute()
        self.page.get("https://subway.simba.taobao.com/")
        self.page.handle_alert(accept=True)
        if self.page("x://a[@class='btn min-width-60']", timeout=6):
            log_.info("正在点击取消弹窗")
            MockTap(ele="x://a[@class='btn min-width-60']", msg="点击取消弹窗失败")(self.page)
        log_.info("正在点击推广")
        MockTap(ele="推广", msg="点击[推广]失败", before_delay=(2, 4), reduce_scope=(3, 5))(self.page)
        self.page.set.main_tab(self.page.to_tab(self.page.latest_tab))
        time.sleep(2)
        log_.info("正在点击标准计划")
        self.page('标准计划').click(by_js=True)

        # 由于可能有遮挡所以使用js点击
        self.page("x://th/div/div[contains(@class,'mx-trigger')]").click(by_js=True)
        time.sleep(2)
        self.page("x:(//div[contains(@class,'mx-output-link')]/span)[1]").click(by_js=True)
        time.sleep(2)

        # MockTap(ele='状态', msg='点击[状态下拉框失败]', before_delay=(2, 4))(self.page)
        # MockTap(ele='推广中', msg='点击[推广中]失败', before_delay=(2, 4))(self.page)
        # 这2句用于线上
        log_.info("正在获取每个[推广计划名称]的链接")
        promotion_plan_name = self.page.eles("x://a/div/div[contains(@class, 'hYME_')]/a")
        links = [i.link for i in promotion_plan_name]
        if not links or not promotion_plan_name:
            raise ValueError("获取[推广计划名称]的链接失败,links为None")
        log_.info("读取表格中的关键词列并复制到剪切板")
        copy_excel_section(path=self.excel_path, sheet_name=self.sheet_name, column_index=['关键词'])
        keywords = pyperclip.paste()
        return links, keywords

    def add_keywords(self):
        """
        遍历每个推广计划
        给每个推广计划中的用户选择(product_id)商品添加关键词
        :return:
        """
        links, keywords = self.go_through_train()
        # 读取excel中的关键词列并复制到剪切板
        for plan_index, link in enumerate(links):
            # 1个推广计划名称可以包含多个商品
            log_.info("正在跳转到第{}[推广计划名称]".format(plan_index + 1))
            self.page.get(link)
            time.sleep(2)
            log_.info("正在获取每个[商品]的链接")
            product_ele_s = self.page.eles("x://a[contains(@class, 'multi-text-overflow2')]")
            if product_ele_s is None:
                raise Exception("获取[商品]失败")
            log_.info("第{}[推广计划]中获取了{}[目标商品]".format((plan_index + 1), len(product_ele_s)))
            product_link = [i.link for i in product_ele_s]
            for product_index, product_ele in enumerate(product_ele_s):
                log_.info("正在跳转到[目标商品]页")
                self.page.get(product_link[product_index])
                time.sleep(2)
                for product in self.target_product_map:
                    product_id = product['productId']
                    product_del_promotion_word = product.get('delPromotionWord')
                    if product_id in self.page("x://a[@class='color-3 ml5 mr5']").link:
                        log_.info("正在给第{}[推广计划名称]的第{}[目标商品]添加关键词".format(plan_index + 1,
                                                                                              product_index + 1))
                        if product_del_promotion_word:
                            # 删除推广计划中的旧关键词
                            self.del_promotion_word(self.page)

                        log_.info("正在点击[+添加关键词]")
                        MockTap(ele='+添加关键词', msg='点击[+添加关键词]按钮失败', before_delay=(2, 4),
                                reduce_scope=(10, 3))(self.page)
                        log_.info("正在点击[词推荐]")
                        MockTap(ele='词推荐', msg='点击[词推荐]失败', before_delay=(2, 4), reduce_scope=(3, 5))(
                            self.page)
                        log_.info("正在点击[手动添加关键词]")
                        MockTap(ele='点击此处可手动输入添加关键词', msg='点击[手动添加关键词]失败', before_delay=(2, 4),
                                reduce_scope=(3, 5))(
                            self.page)
                        log_.info("粘贴关键词")
                        pyperclip.copy(keywords)
                        self.ac.key_down(Keys.CTRL).type('v')
                        # 这里流价格筛选与改价格
                        log_.info("正在点击[全选框]")
                        checkbox_eles = self.page.eles("x://tr/th/input[@class='checkbox']")
                        MockTap(ele=checkbox_eles[2], msg='点击[全选框失败]', before_delay=(2, 4), reduce_scope=(3, 5))(
                            self.page)
                        log_.info("修改推广词价格")
                        self.modify_price(self.page, self.percent, self.price_cap)
                        log_.info('正在点击[精准匹配/广泛匹配]下拉框')
                        log_.info("正在点击[全选框]")
                        checkbox_eles = self.page.eles("x://tr/th/input[@class='checkbox']")
                        MockTap(ele=checkbox_eles[2], msg='点击[全选框失败]', before_delay=(2, 4), reduce_scope=(3, 5))(
                            self.page)
                        MockTap(ele="x://div[@class='fr']/div/div[contains(@class,'mx-trigger')]",
                                msg='点击[精准匹配/广泛匹配]下拉框失败', before_delay=(2, 4), reduce_scope=(3, 5))(
                            self.page)
                        log_.info('正在点击[精准匹配/广泛匹配]')
                        MockTap(ele=self.matches_type, msg='点击[精准匹配/广泛匹配]失败', before_delay=(2, 4),
                                reduce_scope=(3, 5))(self.page)
                        if self.is_test_execute:
                            log_.warning('这是测试执行')
                            log_.info('正在点击[取消]')
                            MockTap(ele='.fl btn mr10', msg='点击[取消]失败', before_delay=(2, 4),
                                    reduce_scope=(3, 5))(self.page)
                        else:
                            log_.warning('这是真实执行')
                            MockTap(ele='.fl btn btn-brand mr10', msg='点击[确定]失败', before_delay=(2, 4),
                                    reduce_scope=(3, 5))(self.page)
                            time.sleep(2)
                            MockTap(ele="x://a[@class='alert-close']", msg='点击[关闭]失败', before_delay=(2, 4),
                                    reduce_scope=(3, 5))(self.page)

    @staticmethod
    def del_promotion_word(page):
        """
        删除推广词
        :return:
        """
        log_.info("正在删除推广词")
        Tap("x://thead/tr/th/input[contains(@class, 'checkbox')]", before_delay=(2, 4))(page)
        Tap("x://div[contains(@class, 'operations')]/a[contains(@mxs, ':j')]/i", before_delay=(2, 4))(page)
        page.handle_alert(accept=True)

    @staticmethod
    def modify_price(page, percent: int, price_cap: float):
        """
        修改直通车推广词价格
        :param page: 页面对象
        :param percent: 按照市场价的百分比修改出价
        :param price_cap: 封顶价格
        :return:
        """
        log_.info("正在点击[修改出价]")
        Tap("x://div[contains(@class, 'fr')]/span[contains(@mxs, ':f')]", before_delay=(2, 4))(page)
        log_.info("正在点击[小圈圈]")
        Tap("x://div[contains(@class, 'keyword-popup')]//div[contains(@mxa, ':d')]/label/input", before_delay=(2, 4))(
            page)
        log_.info("正在点击[下拉框]")
        Tap("x://div[contains(@class, 'keyword-popup')]//div[contains(@mxv, 'multiplyType')]")(page)
        log_.info("正在点击[降低]")
        Tap("x://div[contains(@class, 'keyword-popup')]//li[contains(@title, '降低')]/span", before_delay=(2, 4))(page)
        if percent < 100:
            actual_price = 100 - percent
        else:
            # 这里没算清楚，先这样写着
            actual_price = percent
        log_.info("正在输入[降低百分比]")
        Input(vals=actual_price, ele="x://div[contains(@class, 'keyword-popup')]//div[contains(@mxa, ':d')]/input",
              before_delay=(2, 4))(page)
        log_.info("正在点击[确定]")
        Tap("x://div[contains(@class, 'keyword-popup')]//a[contains(@class, 'btn-brand')]", before_delay=(2, 4))(page)
        market_price_list = page.eles("x://tbody/tr[contains(@class, 'hYME_')]/td[contains(@mxa, ':o')]/text()")

        market_price_num_list = []
        for index, market_price in enumerate(market_price_list):
            # 这个循环是检查是否有超出价格上限的词，如果有就修改

            market_price = float(market_price.replace('元', ''))
            market_price_num_list.append(market_price)
        if all(x > price_cap for x in market_price_num_list):
            # 如果所有的词都超出了价格上限，就统一修改
            log_.info("正在点击[全选框]")
            checkbox_eles = page.eles("x://tr/th/input[@class='checkbox']")
            MockTap(ele=checkbox_eles[2], msg='点击[全选框失败]', before_delay=(2, 4), reduce_scope=(3, 5))(page)
            log_.info("正在点击[修改出价]")
            Tap("x://div[contains(@class, 'fr')]/span[contains(@mxs, ':f')]", before_delay=(2, 4))(page)
            log_.info("输入上限价格")
            Input("x://input[@class='input w100 crowd-price-input']", before_delay=(2, 4), vals=price_cap)(page)
            log_.info("正在点击[确定]")
            Tap("x://div[contains(@class, 'keyword-popup')]//a[contains(@class, 'btn-brand')]", before_delay=(2, 4))(
                page)
        else:
            # 如果有词没有超出价格上限，就一个一个修改这些词的价格
            for index, market_price in enumerate(market_price_num_list):
                if market_price > price_cap:
                    log_.info("依然有超出价格上限的词")
                    word_div = page.eles("x://tbody/tr[contains(@class, 'hYME_')]")
                    word_text = word_div[index].ele("x:/td[contains(@mxa, ':n')]").text
                    page("x://div[contains(@mxa, ':e')]/div[contains(@class, 'hYME_')]").scroll.to_top()
                    # 先移动到顶部
                    time.sleep(1)
                    page.scroll.to_see(word_div[index])
                    # 滚轮移动到目标元素
                    Tap(word_div[index].ele("x:/td[contains(@mxa, ':o')]/i"), before_delay=(2, 4))(page)
                    log_.info("正在修改第[{}]个关键词[{}]的出价".format(index + 1, word_text))
                    Tap("x://input[contains(@value, 'custom')]", before_delay=(2, 4))(page)
                    log_.info("正在输入封顶出价")
                    Input(vals=price_cap, ele="x://input[contains(@class, 'crowd-price-input')]", before_delay=(2, 4))(
                        page)
                    log_.info("正在点击[确定]")
                    MockTap(ele="x://div[contains(@mxs, ':b')]/a[contains(@class, 'btn-brand')]", before_delay=(2, 4),
                            reduce_scope=(11, 7))(page)
